// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//


#pragma once

#include <melon/synchronization/call_once.h>

#include <string>
#include <vector>

namespace kumo::pollux::process {
    ///////////////////////////////////////////////////////////////////////////////

    // TODO: Deprecate in favor of melon::symbolizer.
    class StackTrace {
    public:
        /**
         * Translate a frame pointer to file name and line number pair.
         */
        static std::string translateFrame(void *framePtr, bool lineNumbers = true);

        /**
         * Demangle a function name.
         */
        static std::string demangle(const char *mangled);

    public:
        /**
         * Constructor -- saves the current stack trace. By default, we skip the
         * frames for StackTrace::StackTrace.  If you want those, you can pass
         * '-2' to skipFrames.
         */
        explicit StackTrace(int32_t skipFrames = 0);

        StackTrace(const StackTrace &other);

        StackTrace &operator=(const StackTrace &other);

        /**
         * Generate an output of the written stack trace.
         */
        const std::string &toString() const;

        /**
         * Generate a vector that for each position has the title of the frame.
         */
        const std::vector<std::string> &toStrVector() const;

        /**
         * Return the raw stack pointers.
         */
        const std::vector<void *> &getStack() const {
            return bt_pointers_;
        }

        /**
         * Log stacktrace into a file under /tmp. If "out" is not null,
         * also store translated stack trace into the variable.
         * Returns the name of the generated file.
         */
        std::string log(const char *errorType, std::string *out = nullptr) const;

    private:
        /**
         * Record bt pointers.
         */
        void create(int32_t skipFrames);

    private:
        std::vector<void *> bt_pointers_;
        mutable melon::once_flag bt_vector_flag_;
        mutable std::vector<std::string> bt_vector_;
        mutable melon::once_flag bt_flag_;
        mutable std::string bt_;
    };

    ///////////////////////////////////////////////////////////////////////////////
} // namespace kumo::pollux::process
